import logging
import repo_path
import dep_graph.cache_view
import inspect
import time


logger = logging.getLogger(__name__)

class RuleError(repo_path.Error):
  """Error with a rule."""

class GenRulePaused(object):
  completed = False

  def __init__(self, call_state, fn, fname, name, args, kwargs, pos):
    self.call_state = call_state
    self.fn = fn
    self.pos = pos
    self.fname = fname
    self.name = name
    self.args = args
    self.kwargs = kwargs
    self.output = None

  def run(self):
    self.running = True
    self.call_state.file_stack_calling.append(self.fname)
    dashes = self.call_state.get_dashes()
    logger.info('%s running %s:%s %s',
                dashes, self.fname, self.name, str(self.fn))
    start_time = time.time()
    self.fn.fn_call(self.name, self.args, self.kwargs, self.pos)
    logger.info('%s done %s:%s in %d seconds',
                dashes, self.fname, self.name, time.time() - start_time)
    self.call_state.file_stack_calling.pop()
    self.running = False
    self.completed = True

  def get(self):
    if not self.completed:
      self.run()
    if self.output:
      return self.output
    else:
      raise repo_path.Error("Problem with the genrule for: " + 
          self.fname + ":" + self.name + " no such rule created")

  def set_output(self, out):
    self.output = out


class GenRuleFunc(object):
  def __init__(self, call_state, fn):
    self.call_state = call_state
    self.fn = fn

  def __call__(self, name, *args, **kwargs):
    pos = inspect.getouterframes(inspect.currentframe())[1]
    if len(self.call_state.file_stack) >= 1:
      fname = self.call_state.file_stack[-1]
      logger.debug("storing " + fname + ":" + name)
      self.call_state.announcePaused(fname, name, 
          GenRulePaused(self.call_state, self, fname, name, args, kwargs, pos))
    else:
      return self.fn_call(name, args, kwargs, pos)

  def fn_call(self, name, args, kwargs, pos):
    try:
      fn = self.fn
      return fn(name, *args, **kwargs)
    except (TypeError, repo_path.Error, dep_graph.cache_view.Error) as e:
      (frame, filename, line_number, function_name, lines, index) = pos
      fname = self.call_state.getCallingFile()
      if fname == '.':
        fname = ''
      raise RuleError(''.join(['//', fname, ':', name, '  => ', str(e),
                               '\n    from ', filename, ':', str(line_number)]))

